#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "Types.h"
#include "app_xml.h"
#include "mxml.h"

ULONG xml_loadString(IN CHAR *pcString, INOUT XML_NODE_s **ppstNodeRoot)
{ 
    mxml_node_t *pstRoot = NULL;

    if (pcString == NULL || ppstNodeRoot == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    pstRoot = mxmlLoadString(NULL, pcString, MXML_OPAQUE_CALLBACK);
    if (pstRoot == NULL)
    {
        return STAT_ERR_XML_LOAD;
    }

    *ppstNodeRoot = (XML_NODE_s *)pstRoot;

    return STAT_SUCCEED;
}

ULONG xml_loadFile(IN CHAR *pcFilePath, INOUT XML_NODE_s **ppstNodeRoot)
{
    FILE *pstFile = NULL;
    mxml_node_t *pstRoot = NULL;

    if (pcFilePath == NULL || ppstNodeRoot == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    pstFile = fopen(pcFilePath, "rb");
    if (pstFile == NULL)
    {
        return STAT_ERR_FILE_OPEN;
    }

    //MXML_OPAQUE_CALLBACK can fix getting node text, like : <abc>aa bb cc</abc>
    pstRoot = mxmlLoadFile(NULL, pstFile, MXML_OPAQUE_CALLBACK);
    fclose(pstFile);
    if (pstRoot == NULL)
    {
        return STAT_ERR_XML_LOAD;
    }

    *ppstNodeRoot = (XML_NODE_s *)pstRoot;

    return STAT_SUCCEED;
}

#if 0
const char *whitespace_cb(mxml_node_t *node, int where)
    static const char *tabs = "\t\t\t\t\t\t\t\t";
{
    mxml_node_t	*parent;		/* Parent node */
    mxml_node_t *child;
    INT32 level = -1;
    const char	*name;			/* Name of element */
   
    name = mxmlGetElement(node);
    
    for (level = -1, parent = mxmlGetParent(node); parent; level ++, parent = mxmlGetParent(parent))
    {
        printf("[%s %d] name = %s\n", __FUNCTION__, __LINE__, mxmlGetElement(parent));
    }

    if (level > 8)
        level = 8;
    else if (level < 0)
        level = 0;

    printf("[%s %d] level = %d\n", __FUNCTION__, __LINE__, level);
    printf("[%s %d] name = [%s] where %d\n", __FUNCTION__, __LINE__, name, where);

    if (where == MXML_WS_BEFORE_OPEN)
    {
	if (strncmp(name, "![CDATA[", strlen("![CDATA[")))
            return (tabs + 8 - level);
    }
    else if (where == MXML_WS_AFTER_CLOSE)
    {
    	return ("\n");
    }
    else if (where == MXML_WS_AFTER_OPEN)
    {
        child = mxmlGetFirstChild(node);
        if (mxmlGetFirstChild(child))
            return ("\n");
    }
    else if (where == MXML_WS_BEFORE_CLOSE)
    {
        child = mxmlGetFirstChild(node);
        if (mxmlGetFirstChild(child))
            return (tabs + 8 - level);
    }

    return (NULL);
}
#endif

ULONG xml_saveFile(IN XML_NODE_s *pstNodeRoot, IN CHAR *pcFilePath)
{
    INT32 iRet = 0;
    FILE *pstFile = NULL;
    mxml_node_t *pstRoot = (mxml_node_t *)pstNodeRoot;

    if (pcFilePath == NULL || pstNodeRoot == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    pstFile = fopen(pcFilePath, "w+");
    if (pstFile == NULL)
    {
        return STAT_ERR_FILE_OPEN;
    }

    iRet = mxmlSaveFile(pstRoot, pstFile, MXML_NO_CALLBACK);
    fclose(pstFile);
    if (iRet != 0)
    {
        return STAT_ERR_XML_SAVE;
    }

    return STAT_SUCCEED;
}

ULONG xml_destory(INOUT XML_NODE_s **ppstNodeRoot)
{
    mxml_node_t **ppstRoot = (mxml_node_t **)ppstNodeRoot;

    if (ppstRoot == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    mxmlDelete(*ppstRoot);
    *ppstRoot = NULL;

    return STAT_SUCCEED;
}

ULONG xml_getNodeByPath(IN XML_NODE_s *pstNodeRoot, IN CHAR *pcPath, OUT XML_NODE_s **ppstNode)
{
    mxml_node_t *pstRoot = (mxml_node_t *)pstNodeRoot;
    mxml_node_t *pstNode = NULL;

    if (pstRoot == NULL || pcPath == NULL || ppstNode == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    pstNode = mxmlFindPath(pstRoot, pcPath);
    if (pstNode == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    *ppstNode = (XML_NODE_s *)pstNode;

    return STAT_SUCCEED;
}

ULONG xml_getChildByName(IN XML_NODE_s *pstParentNode, IN CHAR *pcName, OUT XML_NODE_s **ppstNode)
{
    mxml_node_t *pstParent = (mxml_node_t *)pstParentNode;
    mxml_node_t *pstNode = NULL;

    if (pstParent == NULL || pcName == NULL || ppstNode == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    pstNode = mxmlFindElement(pstParent, pstParent, pcName, NULL, NULL, MXML_DESCEND);
    if (pstNode == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    *ppstNode = (XML_NODE_s *)pstNode;

    return STAT_SUCCEED;
}

//作用:找到ptParent的第一个名为szName的孩子节点
ULONG xml_getFirstChildByName(XML_NODE_s *pstParentNode, IN CHAR *szName, OUT XML_NODE_s **ppstNode)
{
    mxml_node_t *pstChild = NULL;
    mxml_node_t *pstParent = (mxml_node_t *)pstParentNode;

    if (pstParent == NULL || szName == NULL || ppstNode == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    ///1 没有任何孩子节点
    pstChild = mxmlGetFirstChild(pstParent);
    if (pstChild == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }
 
    ///2 第1个孩子节点正是期望的
    if ((mxmlGetType(pstChild) == MXML_ELEMENT) &&
        (strcmp(szName, mxmlGetElement(pstChild)) == 0))
    {
        *ppstNode = (XML_NODE_s *)pstChild;
        return STAT_SUCCEED;
    }
 
    ///3 第1个孩子节点不是期望的
    return xml_getNextSiblingByName((XML_NODE_s *)pstChild, szName, ppstNode);
}

//作用: 找到ptNode的下一个名字为szName的兄弟节点
ULONG xml_getNextSiblingByName(XML_NODE_s *pstNode, IN CHAR *szName, OUT XML_NODE_s **ppstNode)
{
    mxml_node_t *ptSibling = (mxml_node_t *)pstNode;

    if (NULL == ptSibling || NULL == szName || NULL == ppstNode)
    {
        return STAT_ERR_XML_NONEXIT;
    }
 
    ptSibling = mxmlGetNextSibling(ptSibling);
    while (ptSibling)
    {
        if (MXML_ELEMENT == mxmlGetType(ptSibling) && 0 == strcmp(szName, mxmlGetElement(ptSibling)))
        {
            *ppstNode = (XML_NODE_s *)ptSibling;
            break;
        }
 
        ptSibling = mxmlGetNextSibling(ptSibling);
    }
    
    if (ptSibling == NULL)
    {
        *ppstNode = NULL;
        return STAT_ERR_XML_NONEXIT;
    }
 
    return STAT_SUCCEED;
}

ULONG xml_getNodeAttrStr(IN XML_NODE_s *pstNode, IN CHAR *pcAttrName, IN UINT32 uLen, INOUT CHAR *pcText)
{
    const CHAR *szValue = NULL;
    mxml_node_t *pstPoint = (mxml_node_t *)pstNode;

    if (pstPoint == NULL || pcAttrName == NULL || pcText == NULL || uLen == 0)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    szValue = mxmlElementGetAttr(pstPoint, pcAttrName);
    if (szValue == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    snprintf(pcText, uLen, "%s", szValue);

    return STAT_SUCCEED;
}

ULONG xml_getNodeAttrInt(XML_NODE_s *pstNode, IN CHAR *szAttrName, OUT INT32 *ps32Value)
{
    CHAR szBuf[64] = {0};
    ULONG uRet = 0;

    uRet = xml_getNodeAttrStr(pstNode, szAttrName, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }

    if (ps32Value != NULL)
    {
        *ps32Value = atoi(szBuf);
    }
    
    return STAT_SUCCEED;
}

ULONG xml_getNodeAttrU32(XML_NODE_s *pstNode, IN CHAR *szAttrName, OUT UINT32 *pu32Value)
{
    CHAR szBuf[64] = {0};
    ULONG uRet = 0;

    uRet = xml_getNodeAttrStr(pstNode, szAttrName, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }

    if (pu32Value != NULL)
    {
        *pu32Value = strtoul(szBuf, NULL, 0);
    }
    
    return STAT_SUCCEED;
}

ULONG xml_getNodeAttrDouble(XML_NODE_s *pstNode, IN CHAR *szAttrName, OUT DOUBLE *pdfValue)
{
    CHAR szBuf[64] = {0};
    ULONG uRet = 0;

    uRet = xml_getNodeAttrStr(pstNode, szAttrName, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }

    if (pdfValue != NULL)
    {
        *pdfValue = strtod(szBuf, NULL);
    }
    
    return STAT_SUCCEED;
}

ULONG xml_setNodeAttrStr(IN XML_NODE_s *pstNode, IN CHAR *pcAttrName, IN CHAR *attr)
{
    if (pstNode == NULL || pcAttrName == NULL || attr == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    mxmlElementSetAttr((mxml_node_t *)pstNode, pcAttrName, attr);

    CHAR szValue[STRING_LEN_512] = {0};
    ULONG uRet = 0;

    uRet = xml_getNodeAttrStr(pstNode, pcAttrName, sizeof(szValue), szValue);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }

    if (strcmp(szValue, attr) != 0)
    {
       return STAT_ERR_XML_SET_ATTR;
    }
    
    return STAT_SUCCEED;
}

ULONG xml_setNodeAttrInt(IN XML_NODE_s *ptNode, IN CHAR *szAttrName, IN INT32 s32Value)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%d", s32Value);
   
    return xml_setNodeAttrStr(ptNode, szAttrName, szBuf);
}

ULONG xml_setNodeAttrU32(IN XML_NODE_s *ptNode, IN CHAR *szAttrName, IN UINT32 u32Value)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%u", u32Value);
   
    return xml_setNodeAttrStr(ptNode, szAttrName, szBuf);
}

ULONG xml_setNodeAttrDouble(IN XML_NODE_s *ptNode, IN CHAR *szAttrName, IN DOUBLE dfValue)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%lf", dfValue);
   
    return xml_setNodeAttrStr(ptNode, szAttrName, szBuf);
}

ULONG xml_getNodeValueCData(IN XML_NODE_s *ptNode, IN UINT32 uIndex, IN UINT32 uLen, INOUT CHAR *pcText)
{
    mxml_node_t *pstParent = (mxml_node_t *)ptNode;
    mxml_node_t *pstNode = NULL;
    UINT32 i = 0;
    const CHAR *szText = NULL;

    pstNode = mxmlGetFirstChild(pstParent);
    if (pstNode == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    szText = mxmlGetCDATA(pstNode);
    if (szText == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    while (i < uIndex)
    {
        pstNode = mxmlGetNextSibling(pstNode);
	if (pstNode == NULL)
        {
            break;
        }

        szText = mxmlGetCDATA(pstNode);
        if (szText == NULL)
        {
            break;
        }

	i++;
    }

    if (i == uIndex)
    {
    	snprintf(pcText, uLen, "%s", szText);
	return STAT_SUCCEED;
    }

    return STAT_ERR_XML_NONEXIT;
}

ULONG xml_getNodeValueStr(IN XML_NODE_s * pstNode, IN UINT32 uLen, OUT CHAR *pcTxt)
{
    mxml_node_t *pstPoint = (mxml_node_t *)pstNode;
    const CHAR *pcOpaque = NULL;

    if (pstPoint == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    pcOpaque = mxmlGetOpaque(pstPoint);
    if (pcOpaque != NULL)
    {
        snprintf(pcTxt, uLen, "%s", pcOpaque);
    }
    
    return STAT_SUCCEED;
}

ULONG xml_getNodeValueInt(IN XML_NODE_s *pstNode, OUT INT32* ps32Value)
{
    CHAR szValue[64] = { 0 };
    ULONG uRet = STAT_SUCCEED;
    
    if (pstNode == NULL || ps32Value == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }
    
    uRet = xml_getNodeValueStr(pstNode, sizeof(szValue), szValue);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
	*ps32Value = atoi(szValue);
    
    return STAT_SUCCEED;
}

ULONG xml_getNodeValueU32(IN XML_NODE_s *pstNode, OUT UINT32* pu32Value)
{
    CHAR szBuf[64] = { 0 };
    ULONG uRet = STAT_SUCCEED;
    
    if (pstNode == NULL || pu32Value == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }
    
    uRet = xml_getNodeValueStr(pstNode, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
    *pu32Value = strtoul(szBuf, NULL, 0);
    
    return STAT_SUCCEED;
}

ULONG xml_getNodeValueDouble(IN XML_NODE_s *pstNode, OUT DOUBLE *pdfValue)
{
    CHAR szBuf[64] = { 0 };
    ULONG uRet = STAT_SUCCEED;
    
    if (pstNode == NULL || pdfValue == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }
    
    uRet = xml_getNodeValueStr(pstNode, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
    *pdfValue = strtod(szBuf, NULL);
    
    return STAT_SUCCEED;
}

ULONG xml_setNodeValueStr(IN XML_NODE_s * pstNode, IN CHAR *pcTxt)
{
    mxml_node_t *pstPoint = (mxml_node_t *)pstNode;

    if (pstNode == NULL || pcTxt == NULL)
	{
		return STAT_ERR_INVAILD_PARAM;
	}

    if (mxmlGetOpaque(pstPoint) != NULL)
    {
        if (mxmlSetOpaque(pstPoint, pcTxt) != 0)
        {
            return STAT_ERR_XML_SET_OPAQUE;
        }
    }
    else
    {
        if (mxmlNewOpaque(pstPoint, pcTxt) == NULL)
        {
            return STAT_ERR_XML_NEW_OPAQUE;
        }
    }

    return STAT_SUCCEED;
}

ULONG xml_setNodeValueInt(IN XML_NODE_s *pstNode, IN INT32 s32Value)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%d", s32Value);
    
    return xml_setNodeValueStr(pstNode, szBuf);
}

ULONG xml_setNodeValueU32(IN XML_NODE_s *pstNode, IN UINT32 u32Value)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%u", u32Value);
    
    return xml_setNodeValueStr(pstNode, szBuf);
}

ULONG xml_setNodeValueDouble(IN XML_NODE_s *pstNode, IN DOUBLE df32Value)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%lf", df32Value);
    
    return xml_setNodeValueStr(pstNode, szBuf);
}

ULONG xml_setNodeValueCData(IN XML_NODE_s *ptNode, IN UINT32 uIndex, IN CHAR *pcTxt)
{
    mxml_node_t *pstParent = (mxml_node_t *)ptNode;
    mxml_node_t *pstNode = NULL;
    UINT32 i = 0;
    const CHAR *szText = NULL;

    pstNode = mxmlGetFirstChild(pstParent);
    if (pstNode == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    szText = mxmlGetCDATA(pstNode);
    if (szText == NULL)
    {
        return STAT_ERR_XML_NONEXIT;
    }

    while (i < uIndex)
    {
        pstNode = mxmlGetNextSibling(pstNode);
        if (pstNode == NULL)
        {
            break;
        }

        szText = mxmlGetCDATA(pstNode);
        if (szText == NULL)
        {
            break;
        }

        i++;
    }

    if (i == uIndex)
    {
        if (mxmlSetCDATA(pstNode, pcTxt) != 0)
        {
            return STAT_ERR_XML_SET_CDATA;
        }
    }
    else
    {
        if (mxmlNewCDATA(pstParent, pcTxt) == NULL)
        {
            return STAT_ERR_XML_NEW_CDATA;
        }
    }
    
    return STAT_SUCCEED;
}

ULONG xml_getSonNodeValueStr(IN XML_NODE_s *pstParent, IN CHAR *szNodeName, IN UINT32 uLen, INOUT CHAR *pcText)
{
    ULONG uRet = STAT_SUCCEED;
    XML_NODE_s *pstNode = NULL;
    
    uRet = xml_getChildByName(pstParent, szNodeName, &pstNode);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
    return xml_getNodeValueStr(pstNode, uLen, pcText);
}

ULONG xml_getSonNodeValueInt(IN XML_NODE_s *pstParent, IN CHAR *szNodeName, INOUT INT32 *ps32Value)
{
    CHAR szBuf[64] = {0};
    ULONG uRet = STAT_SUCCEED;

    uRet = xml_getSonNodeValueStr(pstParent, szNodeName, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
    if (ps32Value != NULL)
    {
        *ps32Value = atoi(szBuf);
    }

    return STAT_SUCCEED;
}

ULONG xml_getSonNodeValueU32(IN XML_NODE_s *pstParent, IN CHAR *szNodeName, INOUT UINT32 *pu32Value)
{
    CHAR szBuf[64] = {0};
    ULONG uRet = STAT_SUCCEED;

    uRet = xml_getSonNodeValueStr(pstParent, szNodeName, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
    if (pu32Value != NULL)
    {
        *pu32Value = strtoul (szBuf, NULL, 0);
    }

    return STAT_SUCCEED;
}

ULONG xml_getSonNodeValueDouble(IN XML_NODE_s *pstParent, IN CHAR *szNodeName, INOUT DOUBLE *pdfValue)
{
    CHAR szBuf[64] = {0};
    ULONG uRet = STAT_SUCCEED;

    uRet = xml_getSonNodeValueStr(pstParent, szNodeName, sizeof(szBuf), szBuf);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
    if (pdfValue != NULL)
    {
        *pdfValue = strtod (szBuf, NULL);
    }

    return STAT_SUCCEED;
}

ULONG xml_getSonNodeValueCData(IN XML_NODE_s *pstParent, IN CHAR *szNodeName, IN UINT32 uLen, INOUT CHAR *pcText)
{
    ULONG uRet = STAT_SUCCEED;
    XML_NODE_s *pstNode = NULL;
    
    uRet = xml_getChildByName(pstParent, szNodeName, &pstNode);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
    
    return xml_getNodeValueCData(pstNode, 0, uLen, pcText);
}

//作用: 在父节点下面，生成一个节点
ULONG xml_NewChildElement(IN XML_NODE_s *ptRootNode, IN CHAR *pcPath, IN CHAR *pcNodeName, INOUT mxml_node_t **pstNewChild)
{
    ULONG uRet = STAT_SUCCEED;
    mxml_node_t *pstParent = NULL;

    if (NULL == ptRootNode || NULL == pcPath || NULL == pcNodeName || NULL == pstNewChild)
    {
        return STAT_ERR_INVAILD_PARAM;
    }
 
    uRet = xml_getNodeByPath(ptRootNode, pcPath, (XML_NODE_s **)&pstParent);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
 
    *pstNewChild = mxmlNewElement(pstParent, pcNodeName);
    if (pstNewChild == NULL)
    {
        return STAT_ERR_XML_NEW_ELEM;
    }
    
    return STAT_SUCCEED;
}

ULONG xml_addNodeStr(IN XML_NODE_s *ptRootNode, IN CHAR *pcPath, IN CHAR *pcNodeName, IN CHAR *szValue)
{
    ULONG uRet = STAT_SUCCEED;
    mxml_node_t *ptElem = NULL;
    mxml_node_t *ptCDATA = NULL;
 
    uRet = xml_NewChildElement(ptRootNode, pcPath, pcNodeName, &ptElem);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
 
    if (szValue != NULL)
    {
        ptCDATA = mxmlNewOpaque(ptElem, szValue);
        if (NULL == ptCDATA)
        {
            mxmlDelete(ptElem);
            return STAT_ERR_XML_NEW_CDATA;
        }
    }

    return STAT_SUCCEED;
}

ULONG xml_addNodeInt(IN XML_NODE_s *ptRootNode, IN CHAR *pcPath, IN CHAR *pcNodeName, IN INT32 s32Value)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%d", s32Value);
   
    return xml_addNodeStr(ptRootNode, pcPath, pcNodeName, szBuf);
}

ULONG xml_addNodeU32(IN XML_NODE_s *ptRootNode, IN CHAR *pcPath, IN CHAR *pcNodeName, IN UINT32 u32Value)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%u", u32Value);
   
    return xml_addNodeStr(ptRootNode, pcPath, pcNodeName, szBuf);
}

ULONG xml_addNodeDouble(IN XML_NODE_s *ptRootNode, IN CHAR *pcPath, IN CHAR *pcNodeName, IN DOUBLE dfValue)
{
    CHAR szBuf[64] = {0};
    
    snprintf(szBuf, sizeof(szBuf), "%lf", dfValue);
   
    return xml_addNodeStr(ptRootNode, pcPath, pcNodeName, szBuf);
}

ULONG xml_addNodeCDATA(IN XML_NODE_s *ptRootNode, IN CHAR *pcPath, IN CHAR *pcNodeName, IN CHAR *szData)
{
    ULONG uRet = 0;
    mxml_node_t *ptElem = NULL;
    mxml_node_t *ptCDATA = NULL;
 
    uRet = xml_NewChildElement(ptRootNode, pcPath, pcNodeName, &ptElem);
    if (uRet != STAT_SUCCEED)
    {
        return uRet;
    }
 
    if (NULL != szData)
    {
        ptCDATA = mxmlNewCDATA(ptElem, szData);
        if (NULL == ptCDATA)
        {
            mxmlDelete(ptElem);
            return STAT_ERR_XML_NEW_CDATA;
        }
    }
    
    return STAT_SUCCEED;
}
